package cn.juque.workflow.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.exception.AppException;
import cn.juque.jdfsystem.api.FileInfoClient;
import cn.juque.workflow.entity.ProcessInfo;
import cn.juque.workflow.mapper.ProcessInfoMapper;
import cn.juque.workflow.service.IProcessInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author JUQUE
 * @version 1.0.0
 * <ul>
 *  <li>simple-generator</li>
 *  <li>流程信息</li>
 * </ul>
 * @date 2023-01-27 15:45:40
 **/
@Slf4j
@Service("processInfoService")
public class ProcessInfoServiceImpl implements IProcessInfoService {

    @Resource
    private ProcessInfoMapper processInfoMapper;

    @Resource
    private FileInfoClient fileInfoClient;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private IdentityService identityService;

    @Resource
    private RepositoryService repositoryService;

    /**
     * 分页查询
     *
     * @param pageInfo    pageInfo
     * @param processInfo processInfo
     * @return DataGrid
     */
    @Override
    public List<ProcessInfo> listInfoWithPage(PageInfo pageInfo, ProcessInfo processInfo) {
        Page<ProcessInfo> page = new Page<>(pageInfo.getPage(), pageInfo.getLimit());
        List<ProcessInfo> list = this.processInfoMapper.queryInfoList(page, processInfo);
        pageInfo.setTotal(page.getTotal());
        return list;
    }

    /**
     * 查询
     *
     * @param processInfo processInfo
     * @return List
     */
    @Override
    public List<ProcessInfo> listInfoWithoutPage(ProcessInfo processInfo) {
        return this.processInfoMapper.queryInfoList(processInfo);
    }

    /**
     * 详情
     *
     * @param id 主键
     * @return ProcessInfo
     */
    @Override
    public ProcessInfo detail(String id) {
        return this.processInfoMapper.selectById(id);
    }

    /**
     * 保存
     *
     * @param fileName 文件名称
     * @param content  文件内容
     * @return 部署ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String saveInfo(String fileName, String content) {
        byte[] byteArray = Base64.decode(content);
        String fileId = this.fileInfoClient.upload(fileName, byteArray);
        Deployment deployment = this.repositoryService.createDeployment()
                .addInputStream(fileName, IoUtil.toStream(byteArray))
                .name(fileName).deploy();
        ProcessInfo query = new ProcessInfo();
        query.setProcessName(fileName);
        List<ProcessInfo> list = this.processInfoMapper.selectList(new QueryWrapper<>(query));
        if (CollUtil.isNotEmpty(list)) {
            ProcessInfo source = list.get(0);
            source.setDeployId(deployment.getId());
            source.setFileId(fileId);
            this.processInfoMapper.updateById(source);
            return deployment.getId();
        }
        ProcessInfo processInfo = new ProcessInfo();
        processInfo.setProcessName(fileName);
        processInfo.setDeployId(deployment.getId());
        processInfo.setFileId(fileId);
        boolean flag = SqlHelper.retBool(this.processInfoMapper.insert(processInfo));
        if (!flag) {
            throw new AppException(MessageEnum.SAVE_FAIL);
        }
        this.fileInfoClient.trustFile(CollUtil.newArrayList(fileId), CollUtil.newArrayList());
        return deployment.getId();
    }

    /**
     * 创建流程实例
     *
     * @param processDefinitionKey 流程KEY
     * @param businessKey          业务ID
     * @param initiator            发起人
     * @param variableMap          变量
     * @return 实例id
     */
    @Override
    public String createInstance(String processDefinitionKey, String businessKey, String initiator, Map<String, Object> variableMap) {
        this.identityService.setAuthenticatedUserId(initiator);
        ProcessInstance processInstance = this.runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variableMap);
        log.info("create process instance successful, instance id:{}", processInstance.getProcessInstanceId());
        return processInstance.getProcessInstanceId();
    }

    /**
     * 删除
     *
     * @param ids 主键列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteInfo(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        List<ProcessInfo> processList = this.processInfoMapper.selectBatchIds(ids);
        int count = this.processInfoMapper.deleteBatchIds(ids);
        if (count != ids.size()) {
            throw new AppException(MessageEnum.DELETE_FAIL);
        }

        processList.forEach(f -> this.repositoryService.deleteDeployment(f.getDeployId()));
    }
}
